using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Ltf.Remoting.Commands;
using Ltf.Remoting.TeamFoundation;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.IO;
using Ltf.Remoting.TFAccess;
using Ltf.MonitorLizard.Helpers;
using Ltf.Remoting.RemoteEvents;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace Ltf.MonitorLizard.Forms
{
	[FormType(FormTypes.History)]

	public partial class HistorySelector : Form
	{
		private Stack<string> pathViewHistory = new Stack<string>();
		private bool includeWorkitems = false;
		private TFHistory currentHistory;
		private bool isBranchHistoryRequired;

		private TFServerConnection connection;

		public HistorySelector(string[] pathList, LizardEventArgs args)
			: this(pathList[0])
		{ }

		public HistorySelector(string path)
		{
			InitializeComponent();
			connection = ServerConnections.GetConnectionForPath(path);
			workspace = connection.GetWorkspace(path);
			btnCancel.Text = "E&xit";
			btnOkay.Visible = false;
			ShowHistory(path);
		}

		public HistorySelector(string serverPath, TFServerConnection connection, Workspace workspace)
		{
			this.connection = connection;
			InitializeComponent();
			this.workspace = workspace;
			btnCancel.Text = "E&xit";
			btnOkay.Visible = false;
			path = serverPath;
			ShowHistory(path);
		}


		public HistorySelector(TFServerConnection connection, Workspace workspace)
		{
			this.connection = connection;
			this.workspace = workspace;
			InitializeComponent();
			lvwHistory.MouseDown += new MouseEventHandler(lvwHistory_MouseDown);
			lvwHistory.Click += new EventHandler(lvwHistory_Click);
		}

		public HistorySelector(ComboBox versionPicker, TFServerConnection connection, Workspace workspace)
			: this(connection, workspace)
		{
			versionPicker.SelectedValueChanged += new EventHandler(versionPicker_SelectedValueChanged);
		}

		protected override void OnShown(EventArgs e)
		{
			base.OnShown(e);
		}
		public Workspace Workspace
		{
			get { return workspace; }
			set { workspace = value; }
		}


		MouseButtons lastHistoryButton = MouseButtons.Left;

		void lvwHistory_MouseDown(object sender, MouseEventArgs e)
		{
			lastHistoryButton = e.Button;
		}

		public string Path
		{
			get
			{
				return path;
			}
			set
			{
				string name;
				int version;
				LizardFileAccess.GetNameAndVersionFromPath(value, out name, out version);
				path = name;
			}
		}


		void versionPicker_SelectedValueChanged(object sender, EventArgs e)
		{
			ComboBox vp = sender as ComboBox;
			if (LizardFileAccess.IsActivelyLoading(vp))
				return;
			if (vp != null && vp.SelectedItem!=null)
			{
				if (vp.SelectedItem.ToString() == "Browse...")
				{
					int changeSetId = this.PickChangeset(path);
					foreach (object item in vp.Items)
					{
						int cs = -1;
						int.TryParse(item.ToString(), out cs);
						if (cs != -1 && cs == changeSetId)
						{
							vp.SelectedItem = item;
							return;
						}
					}
					vp.SelectedIndex = 0;
				}


			}
		}

		private Workspace workspace = null;
		private int changesetId = -1;
		private Ltf.MonitorLizard.Helpers.FileIcons fileIcons;
		Dictionary<ListView, int> sortColumnIndex;
		Dictionary<ListView, bool> sortDesc;
		string path;
		int version;
		int detailVersion = 0;

		private const int maxSetLength = 10000000;

		private int setLength = maxSetLength;

		public int PickChangeset(string path)
		{
			ShowHistory(path);
			this.ShowDialog();
			return changesetId;
		}



		public void ShowHistory(string path)
		{
			using (BusyIndicator bi = new BusyIndicator("LizardTF History", "Fetching history from server...", false))
			{
				this.path = path;
				pathViewHistory.Push(path);
				tsbPathViewHistoryBack.Enabled = (pathViewHistory.Count > 1);
				if (workspace == null && !path.StartsWith("$"))
					workspace = connection.GetWorkspace(System.IO.Path.GetDirectoryName(path));
				tsbUsePathParent.Enabled = (workspace != null);
				fileIcons = new Ltf.MonitorLizard.Helpers.FileIcons(fileImages);
				txtPath.Text = path;
				this.path = path;
				sortColumnIndex = new Dictionary<ListView, int>();
				sortColumnIndex.Add(lvwHistory, 0);
				sortColumnIndex.Add(lvwDetails, 0);
				sortDesc = new Dictionary<ListView, bool>();
				sortDesc.Add(lvwHistory, false);
				sortDesc.Add(lvwDetails, false);

				lvwHistory.StateImageList = fileImages;

				lvwHistory.Items.Clear();
				if (cmbSetLength.Text == "All")
					setLength = maxSetLength;
				else
					int.TryParse(cmbSetLength.Text, out setLength);
				LoadChangesets();
			}
		}

		private void LoadChangesets()
		{
			LoadChangesets(false);
		}

		private void LoadChangesets(bool isContinuation)
		{
			//int lastIdx = lvwHistory.Items.Count - 1;
			//int lastChangesetId = 1;
			//while (lastIdx >= 0 && lastChangesetId == 1)
			//  int.TryParse(lvwHistory.Items[lastIdx--].Text, out lastChangesetId);

			//List<LizardChangeset> lcs = ItemHistory.GetHistory(path, includeWorkitems, lastChangesetId - 1, setLength);

			if (currentHistory == null || !isContinuation)
			{
				if (path.StartsWith("$"))
					currentHistory = new TFHistory(connection, path, workspace);
				else
					currentHistory = new TFHistory(path);

				if (isBranchHistoryRequired)
					currentHistory.BranchResolutionType = BranchResolutionType.RecursiveBranchToResolution;
				else
					currentHistory.BranchResolutionType = BranchResolutionType.None;
			}

			currentHistory.GetHistory(includeWorkitems, 0, setLength, RecursionType.Full);

			//if (isBranchHistoryRequired)
			//{
			//  string fp = string.Empty;
			//  int cs = currentHistory.GetBranchHistory(new ChangesetVersionSpec(lastChangesetId), ref fp,1000,
			//    includeWorkitems,RecursionType.Full);


			//}
			int lastChangesetId = 0;
			foreach (LizardChangeset lc in currentHistory.Changesets)
			{
				string name = lc.Commiter;
				string[] ps = lc.Commiter.Split('\\');
				if (ps.Length == 2)
					name = ps[1];
				string date = lc.CreationDate.ToString("dd/MM/yy hh:mm");
				ListViewItem lvi = new ListViewItem(new string[] { lc.ChangesetId.ToString(), name, date, lc.Comment, lc.WorkItemIds });

				if (lc.IsFromBranch)
					lvi.ForeColor = Color.Blue;

				lvwHistory.Items.Add(lvi);
				lastChangesetId = lc.ChangesetId;
			}
			int lastIdx = lvwHistory.Items.Count - 1;
			int rem;
			if (setLength != maxSetLength && !currentHistory.IsMainHistoryFinished)
			{
				System.Math.DivRem(currentHistory.Count, setLength, out rem);
				if (lastIdx >= 0 && lvwHistory.Items[lastIdx].Text == "More...")
					lvwHistory.Items.RemoveAt(lastIdx);
				else if (lastIdx >= 0 && rem == 0)
					lvwHistory.Items.Add("More...");
			}
		}

		void lsvChanges_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			ListView lv = sender as ListView;
			lv.Columns[sortColumnIndex[lv]].ImageKey = null;
			if (sortColumnIndex[lv] == e.Column)
				sortDesc[lv] = !sortDesc[lv];
			else
			{
				sortDesc[lv] = false;
				sortColumnIndex[lv] = e.Column;
			}
			lv.ListViewItemSorter = (IComparer)new Sorter(sortColumnIndex[lv], sortDesc[lv]);
			lv.Sort();

		}


		private void lvwHistory_Click(object sender, EventArgs e)
		{
			if (lastHistoryButton == MouseButtons.Left)
			{
				if (lvwHistory.SelectedItems.Count == 1)
				{
					using (BusyIndicator bi = new BusyIndicator("LizardTF History", "Fetching history from server...", false))
					{
						string text = lvwHistory.SelectedItems[0].Text;
						if (text == "More...")
						{
							//lvwHistory.Items.Remove(lvwHistory.SelectedItems[0]);
							lvwHistory.Items.Clear();
							LoadChangesets(true);
							lvwHistory.EnsureVisible(lvwHistory.Items.Count - 1);
						}
						else
						{
							int changesetId = int.Parse(lvwHistory.SelectedItems[0].Text);
							detailVersion = changesetId;
							txtChangeSetInfo.Text = string.Format("Details for changeset #{0}", changesetId);
							Changeset cs = currentHistory.GetChangesetDetails(changesetId);
							ShowChangesets(cs);
						}
					}
				}
				else
				{
					if (lvwHistory.SelectedItems.Count == 1)
					{
						int v = 0;
						int.TryParse(lvwHistory.SelectedItems[0].Text, out v);
						string vpath = path;
						if (!vpath.StartsWith("$"))
							vpath = workspace.GetServerItemForLocalItem(path);
						LizardFileAccess.SetPathVersion(vpath, v);

						ContextMenus.LoadDiffMenu(cmsHistoryMenu, vpath, "Compare with ", connection, workspace);
						cmsHistoryMenu.Show(lvwHistory, lvwHistory.PointToClient(MousePosition));
					}
					else if (lvwHistory.SelectedItems.Count == 2)
					{
						cmsTwoSelectedDiff.Show(lvwHistory, lvwHistory.PointToClient(MousePosition));
					}
				}
			}
		}

		private void ShowChangesets(Changeset cs)
		{
			// optional ??
			Change[] chgs = cs.VersionControlServer.GetChangesForChangeset(cs.ChangesetId, true, 16000, null, null, true);

			
			lvwDetails.Items.Clear();
			lvwDetails.SmallImageList = fileImages;
			lvwDetails.StateImageList = fileImages;
			foreach (Change c in chgs)
			{
			
				ListViewItem lvi = new ListViewItem(new string[] { System.IO.Path.GetFileName(c.Item.ServerItem),c.ChangeType.ToString(),
								System.IO.Path.GetDirectoryName(c.Item.ServerItem)});
				lvi.Tag = c.Item.ServerItem;
				if (c.Item.ItemType == ItemType.Folder)
					lvi.ImageKey = "$folder";
				else
					lvi.ImageKey = fileIcons.LoadIconForFileExtension(System.IO.Path.GetExtension(c.Item.ServerItem));
				lvwDetails.Items.Add(lvi);
			}
			lbxWorkItems.Items.Clear();
			foreach (WorkItem wi in cs.WorkItems)
			{
				lbxWorkItems.Items.Add(string.Format("{0}\t{1}", wi.Id, wi.Title));
			}
		}

		private void btnOkay_Click(object sender, EventArgs e)
		{
			changesetId = -1;
			if (lvwHistory.SelectedItems.Count > 0)
			{
				int.TryParse(lvwHistory.SelectedItems[0].Text, out changesetId);

			}
			this.Close();
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			changesetId = -1;
			this.Close();
		}

		private void lvwDetails_Click(object sender, EventArgs e)
		{
			if (detailMouseButton == MouseButtons.Right)
			{
				string serverItem = lvwDetails.SelectedItems[0].Tag.ToString();
				ItemSpec[] iss = new ItemSpec[] { new ItemSpec(serverItem, RecursionType.None) };
				ExtendedItem[] extItems = GetExtendedItems(iss);

				if (extItems.Length > 0)
				{
					ContextMenus.LoadDiffMenu(cmsHistoryMenu, LizardFileAccess.RevisionPath(extItems[0].SourceServerItem, detailVersion), "Compare with ", connection, workspace);
					cmsHistoryMenu.Show(lvwDetails, lvwDetails.PointToClient(MousePosition));
				}
			}
		}

		private ExtendedItem[] GetExtendedItems(ItemSpec[] iss)
		{
			ExtendedItem[] extItems;
			if (workspace != null)
				extItems = workspace.GetExtendedItems(iss, DeletedState.Any, ItemType.Any)[0];
			else
			{
				extItems = connection.VersionControlServer.GetExtendedItems
							(iss, DeletedState.Any, ItemType.Any)[0];
			}
			return extItems;
		}

		MouseButtons detailMouseButton = MouseButtons.None;
		private void lvwDetails_MouseDown(object sender, MouseEventArgs e)
		{
			detailMouseButton = e.Button;
		}

		private void lvwDetails_DoubleClick(object sender, EventArgs e)
		{
			if (lvwDetails.SelectedItems.Count == 1)
			{
				string serverItem = lvwDetails.SelectedItems[0].Tag.ToString();
				ItemSpec[] iss = new ItemSpec[] { new ItemSpec(serverItem, RecursionType.None) };
				ExtendedItem[] extItems = GetExtendedItems(iss);
				if (extItems.Length > 0 && !string.IsNullOrEmpty(extItems[0].LocalItem))
					ShowHistory(extItems[0].LocalItem);
				else if (extItems.Length > 0 && string.IsNullOrEmpty(extItems[0].LocalItem))
					ShowHistory(extItems[0].SourceServerItem);
				else
					MessageBox.Show("LizardTF can not find a matching repository item for this change, perhaps the file was deleted?",
						"No Repository Item Found", MessageBoxButtons.OK, MessageBoxIcon.Warning);
			}
		}

		private void tsbPathViewHistoryBack_Click(object sender, EventArgs e)
		{
			if (pathViewHistory.Count > 1)
			{
				// remove current
				pathViewHistory.Pop();

				// get previous
				string path = pathViewHistory.Pop();
				ShowHistory(path);

			}
		}

		private void tsbUsePathParent_Click(object sender, EventArgs e)
		{
			string newPath = System.IO.Path.GetDirectoryName(txtPath.Text);
			if (newPath.StartsWith("$"))
				ShowHistory(newPath.Replace("\\", "/"));
			else
			{
				Workspace ws = connection.GetWorkspace(newPath);
				if (ws != null)
					ShowHistory(newPath);
			}
		}

		private void showDifferencesToolStripMenuItem_Click(object sender, EventArgs e)
		{
			int v1 = int.Parse(lvwHistory.SelectedItems[0].Text);
			int v2 = int.Parse(lvwHistory.SelectedItems[1].Text);
			string left = LizardFileAccess.SetPathVersion(workspace.GetServerItemForLocalItem(path), v1);
			string right = LizardFileAccess.SetPathVersion(workspace.GetServerItemForLocalItem(path), v2);
			if (Directory.Exists(path))
			{
				Ltf.MonitorLizard.Forms.DirDiff dd = new Ltf.MonitorLizard.Forms.DirDiff(left, right, connection, connection);
				dd.Show();
				dd.Compare();
			}
			else
			{
				if (System.IO.Path.GetExtension(path) == ".dll" || System.IO.Path.GetExtension(path) == ".exe")
				{
					Ltf.MonitorLizard.Forms.ExecutableDiff ed = new Ltf.MonitorLizard.Forms.ExecutableDiff(left, right);
					ed.Show();
				}
				else
				{
					Ltf.MonitorLizard.Forms.TwoWayDiff twd = new Ltf.MonitorLizard.Forms.TwoWayDiff(left, right, workspace, workspace);
					twd.CompareSideBySide(left, right, false);
					twd.Show();
				}
			}

		}

		private void lvwDetails_SelectedIndexChanged(object sender, EventArgs e)
		{

		}

		private void lvwHistory_DoubleClick(object sender, EventArgs e)
		{
			if (btnOkay.Visible)
				btnOkay_Click(this, new EventArgs());
		}

		private void txtWorkItems_TextChanged(object sender, EventArgs e)
		{

		}

		//private void txtWorkItems_Click(object sender, EventArgs e)
		//{
		//  string s = txtWorkItems.Text.Split('\t')[0];
		//  int wi = int.Parse(s);

		////	WorkItem workItem=ConnectionInstance.Connection.VersionControlServer.getw
		//}

		private void lbxWorkItems_DoubleClick(object sender, EventArgs e)
		{
			if (lbxWorkItems.SelectedIndex >= 0)
			{
				string line = lbxWorkItems.SelectedItem.ToString();
				int wi = int.Parse(line.Split('\t')[0]);
				WorkItemStore wis = new WorkItemStore(connection.TeamFoundationServer);
				WorkItem workItem = wis.GetWorkItem(wi);

				LizardWorkItem lwi = new LizardWorkItem(connection, workItem);
				lwi.Show();

			}
		}

		private void ckbBranchHistory_CheckedChanged(object sender, EventArgs e)
		{
			isBranchHistoryRequired = ckbBranchHistory.Checked;
			ShowHistory(path);
		}

		private void tsbRefresh_Click(object sender, EventArgs e)
		{
			ShowHistory(path);
		}
	}
}